﻿#pragma once
#include<assert.h>

namespace mySTLString
{
    class string
    {
    public:
        typedef char* iterator;
        typedef const char* const_iterator;

        const_iterator begin() const
        {
            return _str;
        }

        const_iterator end() const
        {
            return _str + _size;
        }

        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return _str + _size;
        }

        //构造函数,
        string(const char* str = "")
            :_size(strlen(str))
            ,_capacity(_size)
        {
            _str = new char[_capacity + 1]; //给‘\0’开一个字节的空间
            strcpy(_str, str);  //把str中的元素全部拷贝到_str里
        }

        //拷贝构造函数
        string(const string& s)
            :_size(s._size)
            ,_capacity(s._capacity)
        {
            _str = new char[s._capacity + 1];
            strcpy(_str, s._str);
        }

        //赋值重载，思路：创建一个大小为s._capacity的临时变量并把str中元素全部拷贝到临时变量里，最后让_str
        //指针指向临时变量所在的空间，完成赋值操作。
        string& operator=(const string& s)
        {
            if (this != &s)
            {
                char* tmp = new char[s._capacity + 1];
                strcpy(tmp, s._str);
                delete[] _str;  //释放掉_str,以免_str指向tmp后，
                                //原来的空间任然存在但是找不到造成了内存泄漏
                _str = tmp;
                _size = s._size;
                _capacity = s._capacity;
            }
            return *this;
        }

        //析构函数
        ~string()
        {
            if (_str)   //如果数组不为空才析构
            {
                delete[] _str;
                _str = nullptr;
                _size = 0;
                _capacity = 0;
            }
        }

        const char* c_str() const
        {           
            return _str;
        }

        //重载[]
        char& operator[](size_t pos)
        {
            assert(pos < _size);
            return _str[pos];
        }

        const char& operator[](size_t pos) const
        {
            assert(pos < _size);
            return _str[pos];
        }

        size_t size() const
        {
            return _size;
        }

        size_t capacity() const
        {
            return _capacity;
        }

        //重载+=
        string& operator+=(const char* str)
        {
            append(str);
            return *this;
        }

        string& operator+=(char ch)
        {
            push_back(ch);
            return *this;
        }

        void reserve(size_t n)
        {
            if (n > capacity())
            {
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;     //_size是不用更新的，因为有效数据个数没有改变    
                _capacity = n;
            }
        }

        //resize扩空间 + 初始化，n < size就删除数据，n > _capacity就扩容
        void resize(size_t n, char ch = '\0')
        {
            if (n < size())
            {
                _size = n;
                _str[_size] = '\0';
            }
            else
            {
                if (n > capacity())
                {
                    /*char* tmp = new char[n + 1];
                    strcpy(tmp, _str);
                    delete[] _str;
                    _str = tmp;
                    _capacity = n;*/
                    reserve(n);
                }
                for (size_t i = _size; i < n; i++)
                {
                    _str[i] = ch;
                }
                _size = n;
                _str[_size] = '\0';
            }            
        }

        //尾插
        void push_back(char ch)
        {
            /*if (_size == _capacity)
            {
                size_t newCapacity = _capacity == 0 ? 4 : 2 * _capacity;
                reserve(newCapacity);
            }
            _str[_size] = ch;
            ++_size;
            _str[_size] = '\0';*/
            insert(_size, ch);
        }

        void append(const char* str)
        {
            /*size_t len = _size + strlen(str);
            if (len > _capacity)
            {
                reserve(len);
            }
            strcpy(_str + _size, str);   
            _size = len;*/
            insert(_size, str);
        }

        //在某位置插入一个字符
        string& insert(size_t pos, char ch)
        {
            if (_size == _capacity)
            {
                size_t newCapacity = _capacity == 0 ? 4 : 2 * _capacity;
                reserve(newCapacity);
            }
            size_t end = _size + 1; //连'\0'一起移动
            /*for (size_t i = end; i > pos; --i)
            {
                _str[i] = _str[i - 1];
            }*/
            while (end > pos)
            {
                _str[end] = _str[end - 1];
                --end;
            }
            _str[pos] = ch;
            ++_size;
            return *this;
        }

        //在某位置插入字符串
        string& insert(size_t pos, const char* str)
        {
            size_t len = strlen(str);
            if (len + _size > _capacity)
            {
                reserve(len + _size);
            }
            size_t end = _size + len;
            while (end > pos + len - 1)
            {
                _str[end] = _str[end - len];
                --end;
            }
            strncpy(_str + pos, str, len);
            _size = _size + len;
            return *this;
        }

        //删除，本质上就是挪动数据覆盖
        string& erase(size_t pos, size_t len = npos)    //​len​ 的默认值是 ​npos​，
                                                        //这是一个表示最大可能长度的常量，
                                                        //意味着删除从 ​pos​ 开始直到字符串末尾的所有字符。
        {
            assert(pos < _size);

            if (len == npos || pos + len >= _size)
            {
                _str[pos] = '\0';
                _size = pos;
            }
            else
            {
                size_t begin = pos + len;
                while (begin <= _size)
                {
                    _str[begin - len] = _str[begin];
                    ++begin;
                }
                _size = _size - len;
            }
            return *this;
        }

        //查找字符
        size_t find(char ch, size_t pos = 0)
        {
            for (; pos < _size; ++pos)
            {
                if (_str[pos] == ch)
                {
                    return pos;
                }
            }
            return npos;
        }

        //查找字符串
        size_t find(const char* str, size_t pos = 0)
        {
            const char* tmp = strstr(_str + pos, str);
            if (tmp == nullptr)
            {
                return npos;
            }
            else
            {
                return tmp - _str;
            }
        }
    private:
        char* _str;
        size_t _size;   //有效数据的元素个数
        size_t _capacity;   //数组空间大小

        const static size_t npos;
    };
    
    const size_t string::npos = -1;

    //重载<<
    ostream& operator<<(ostream& out, const string& s)
    {
        for (auto ch : s)
        {
            out << ch;
        }
        return out;
    }

    //重载>>
    istream& operator>>(istream& in, string& s)
    {
        char ch;
        ch = in.get();
        char buff[128] = { '\0' };
        size_t i = 0;
        while (ch != ' ' && ch != '\0')
        {
            buff[i++] = ch;
            if (i == 127)
            {
                s += buff;
                memset(buff, '\0', 128);
                i = 0;
            }
            ch = in.get();
        }
        s += buff;
        return in;
    }

    bool operator<(const string& s1, const string& s2)
    {
        return strcmp(s1.c_str(), s2.c_str()) < 0;
    }

    bool operator==(const string& s1, const string& s2)
    {
        return strcmp(s1.c_str(), s2.c_str()) == 0;
    }

    bool operator<=(const string& s1, const string& s2)
    {
        return s1 < s2 || s1 == s2;
    }

    bool operator>(const string& s1, const string& s2)
    {
        return !(s1 <= s2);
    }

    bool operator>=(const string& s1, const string& s2)
    {
        return !(s1 < s2);
    }

    bool operator!=(const string& s1, const string& s2)
    {
        return !(s1 == s2);
    }
}
